package com.river.boot.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.river.boot.common.base.BasePageQuery;
import com.river.boot.common.base.Option;
import com.river.boot.common.constant.SystemConstants;
import com.river.boot.common.exception.BusinessException;
import com.river.boot.common.result.ResultCode;
import com.river.boot.security.manager.JwtTokenManager;
import com.river.boot.security.utils.SecurityUtils;
import com.river.boot.system.converter.UserConverter;
import com.river.boot.system.mapper.UserMapper;
import com.river.boot.system.model.entity.Role;
import com.river.boot.system.model.entity.User;
import com.river.boot.system.model.form.PasswordUpdateForm;
import com.river.boot.system.model.form.UserForm;
import com.river.boot.system.model.form.UserProfileForm;
import com.river.boot.system.model.query.UserPageQuery;
import com.river.boot.system.model.vo.RoleVO;
import com.river.boot.system.model.vo.UserDetailsVO;
import com.river.boot.system.model.vo.UserPageVO;
import com.river.boot.system.model.vo.UserProfileVO;
import com.river.boot.system.service.RoleMenuService;
import com.river.boot.system.service.UserRoleService;
import com.river.boot.system.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author xiang
 * @description 针对表【sys_user(用户表)】的数据库操作Service实现
 * @createDate 2025-03-20 15:23:50
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    private final JwtTokenManager jwtTokenManager;
    private final PasswordEncoder passwordEncoder;
    private final UserRoleService userRoleService;
    private final RoleMenuService roleMenuService;
    private final UserConverter userConverter;

    @Override
    public Page<UserPageVO> getUserPage(UserPageQuery queryParams) {
        boolean isRoot = SecurityUtils.isRoot();
        queryParams.setIsRoot(isRoot);
        Page<UserPageVO> page = BasePageQuery.page(queryParams);
        return this.baseMapper.getUserPage(page, queryParams);
    }

    @Override
    public UserForm getUserById(Long id) {
        User user = this.getById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        UserForm vo = new UserForm();
        BeanUtils.copyProperties(user, vo);
        List<Role> roleList = userRoleService.getRolesByUserId(id);
        List<Long> roleIds = roleList.stream().map(Role::getId).collect(Collectors.toList());
        vo.setRoleIds(roleIds);
        Set<String> roles = roleList.stream().map(Role::getName).collect(Collectors.toSet());
        vo.setRoles(roles);
        Set<String> permissions = roleMenuService.getPermsByRoleIds(CollUtil.newHashSet(roleIds));
        vo.setPerms(permissions);
        return vo;
    }

    @Override
    public UserDetailsVO getUserDetailsById(Long id) {
        User user = this.getById(id);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        UserDetailsVO vo = new UserDetailsVO();
        BeanUtils.copyProperties(user, vo);
        List<Role> roleList = userRoleService.getRolesByUserId(id);
        Set<Long> roleIds = roleList.stream().map(Role::getId).collect(Collectors.toSet());
        vo.setRoleIds(roleIds);
        Set<RoleVO> roles = roleList.stream().map(RoleVO::from).collect(Collectors.toSet());
        vo.setRoles(roles);
        Set<String> permissions = roleMenuService.getPermsByRoleIds(roleIds);
        vo.setPerms(permissions);
        return vo;
    }

    @Override
    @Transactional
    public Long saveUser(UserForm userForm) {
        String username = userForm.getUsername();

        long count = this.count(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        Assert.isTrue(count == 0, "用户名已存在");

        // 实体转换 form->entity
        User entity = userForm.toEntity(userForm);

        // 设置默认加密密码
        String defaultEncryptPwd = passwordEncoder.encode(SystemConstants.DEFAULT_PASSWORD);
        entity.setPassword(defaultEncryptPwd);

        // 新增用户
        boolean result = this.save(entity);

        if (result) {
            userRoleService.saveUserRoles(entity.getId(), userForm.getRoleIds());
        }
        return entity.getId();
    }

    @Override
    public void deleteUserById(Long id) {
        this.lambdaUpdate().set(User::getIsDeleted, true).eq(User::getId, id).update();
    }

    @Override
    public UserDetailsVO me() {
        Long userId = SecurityUtils.getUserId();
        if (Objects.isNull(userId)) return null;
        return this.getUserDetailsById(userId);
    }

    @Override
    @Transactional
    public boolean updateUser(Long id, UserForm userForm) {
        User user = this.getById(id);
        if (user == null) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }
        BeanUtils.copyProperties(userForm, user);
        boolean result = this.updateById(user);
        if (result) {
            userRoleService.saveUserRoles(id, userForm.getRoleIds());
        }
        return result;
    }

    @Override
    public List<Option<String>> listUserOptions() {
        List<User> list = this.list(new LambdaQueryWrapper<User>()
                .eq(User::getStatus, 1)
        );
        return userConverter.toOptions(list);
    }

    @Override
    public void deleteUserByIds(String idsStr) {
        List<Long> ids = Arrays.stream(idsStr.split(",")).map(Long::parseLong).collect(Collectors.toList());
        this.removeByIds(ids);
    }

    @Override
    public UserProfileVO getUserProfile(Long userId) {
        User user = this.getById(userId);
        if (Objects.isNull(user)) {
            throw new BusinessException(ResultCode.USER_NOT_EXIST);
        }

        return userConverter.toProfile(user);
    }

    /**
     * 修改用户密码
     *
     * @param userId 用户ID
     * @param data   密码修改表单数据
     * @return true|false
     */
    @Override
    public boolean changePassword(Long userId, PasswordUpdateForm data) {

        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }

        String oldPassword = data.getOldPassword();

        // 校验原密码
        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            throw new BusinessException("原密码错误");
        }
        // 新旧密码不能相同
        if (passwordEncoder.matches(data.getNewPassword(), user.getPassword())) {
            throw new BusinessException("新密码不能与原密码相同");
        }

        String newPassword = data.getNewPassword();
        boolean result = this.update(new LambdaUpdateWrapper<User>()
                .eq(User::getId, userId)
                .set(User::getPassword, passwordEncoder.encode(newPassword))
        );

        if (result) {
            // 加入黑名单，重新登录
            String accessToken = SecurityUtils.getTokenFromRequest();
            jwtTokenManager.invalidateToken(accessToken);
        }
        return result;
    }

    /**
     * 修改个人中心用户信息
     *
     * @param formData 表单数据
     * @return true|false
     */
    @Override
    public boolean updateUserProfile(UserProfileForm formData) {
        Long userId = SecurityUtils.getUserId();
        User entity = userConverter.toEntity(formData);
        entity.setId(userId);
        return this.updateById(entity);
    }

    /**
     * 重置密码
     *
     * @param userId   用户ID
     * @param password 密码重置表单数据
     * @return true|false
     */
    @Override
    public boolean resetPassword(Long userId, String password) {
        return this.update(new LambdaUpdateWrapper<User>()
                .eq(User::getId, userId)
                .set(User::getPassword, passwordEncoder.encode(password))
        );
    }
}




